package com.evan.review.classloader;

/**
 * ClassLoader类加载器与反射机制详解及面试要点
 *
 * 一、ClassLoader类加载器基础知识
 *
 * 1. 类加载器的作用
 *    - 作用：将类的字节码（.class文件或dex文件）加载到内存中，转换成Java类型
 *    - 特点：采用双亲委派模型，保证类的唯一性和安全性
 *    - Android与Java区别：Android使用PathClassLoader和DexClassLoader替代URLClassLoader
 *    - 面试考点：了解各种类加载器的职责和使用场景，掌握Android中ClassLoader的特点
 *
 * 2. 类加载器层次结构（Java）
 *    - Bootstrap ClassLoader：加载Java核心类库，由C++实现，在Java中访问为null
 *    - Extension ClassLoader：加载扩展类库，位于jre/lib/ext目录
 *    - Application ClassLoader：加载应用程序classpath路径下的类
 *    - 自定义ClassLoader：继承ClassLoader实现自定义加载逻辑
 *    - 面试考点：掌握类加载器层次结构和各自的职责范围
 *
 * 3. 类加载器层次结构（Android）
 *    - BootClassLoader：Android平台上加载核心类库，在Java层访问也为null
 *    - PathClassLoader：负责加载已安装应用的dex文件（Android默认使用）
 *    - DexClassLoader：可加载外部dex/apk/jar文件，支持动态加载
 *    - 自Android 8.0起，PathClassLoader和DexClassLoader实现代码合并
 *    - 面试考点：理解Android类加载器与Java类加载器的区别
 *
 * 4. 双亲委派机制
 *    - 定义：先将加载请求委托给父加载器，父加载器无法加载时才由子加载器加载
 *    - 过程：子加载器 -> 父加载器 -> 爷爷加载器 -> ... -> Bootstrap ClassLoader
 *    - 作用：1）保证类的唯一性；2）保证核心类的安全性（防止恶意替换java.lang.String等核心类）
 *    - 面试考点：理解委派模式的工作流程、优点和打破双亲委派的场景
 *
 * 5. 类加载过程
 *    - 加载：通过类名获取二进制字节流，生成Class对象
 *    - 连接-验证：确保字节流符合JVM规范，不会危害虚拟机安全
 *    - 连接-准备：为类变量（static成员）分配内存并设置初始值（零值）
 *    - 连接-解析：将常量池内符号引用替换为直接引用
 *    - 初始化：执行类构造器<clinit>方法，包括静态变量赋值和静态代码块
 *    - 面试考点：能区分类加载的各个阶段，特别是初始化时的变量赋值顺序
 *
 * 6. Class.forName与ClassLoader.loadClass区别
 *    - Class.forName：默认会执行类的初始化（静态代码块和静态变量赋值）
 *    - ClassLoader.loadClass：默认不执行初始化（纯粹的加载类）
 *    - 使用场景：JDBC驱动加载使用Class.forName，因需要执行驱动类的静态初始化代码
 *    - Class.forName三参数版本可控制是否初始化和指定类加载器
 *    - 面试考点：理解两者区别并能举例合适的使用场景
 *
 * 7. 破坏双亲委派模型的场景
 *    - JDK1.2之前：无统一的双亲委派模型，需自行重写loadClass()
 *    - JDBC/SPI机制：接口由Bootstrap ClassLoader加载，但实现由AppClassLoader加载
 *    - 上下文类加载器（Thread Context ClassLoader）：解决SPI场景的委派问题
 *    - OSGi/热更新等：需从下往上查找类，先从自己加载再委托父加载器
 *    - 面试考点：了解为什么需要破坏双亲委派和线程上下文类加载器的作用
 *
 * 8. Android中ClassLoader的应用场景
 *    - 插件化开发：加载外部dex文件实现功能扩展
 *    - 热修复：动态加载包含补丁的dex文件修复bug
 *    - 动态加载资源：根据需要加载皮肤、语言包等资源
 *    - MultiDex实现：解决方法数超限问题
 *    - 面试考点：能解释各种技术方案的实现原理中ClassLoader的角色
 *
 * 二、反射（Reflection）机制
 *
 * 1. 反射基本概念
 *    - 定义：在运行时检查、修改类的结构（属性、方法、构造器等）
 *    - 应用场景：框架开发、动态代理、注解处理、泛型擦除后的类型获取等
 *    - 入口：Class类是反射的入口，所有反射API都从Class对象开始
 *    - 面试考点：反射的基本概念和应用场景，反射与注解的关系
 *
 * 2. 获取Class对象的方式
 *    - 方式一：Class.forName("全限定类名")
 *    - 方式二：类名.class
 *    - 方式三：对象.getClass()
 *    - 方式四：ClassLoader.loadClass("全限定类名")
 *    - 面试考点：不同方式的区别和适用场景，特别是是否触发类的初始化
 *
 * 3. 反射获取类成员
 *    - 获取构造方法：getConstructor()/getDeclaredConstructor()
 *    - 获取成员变量：getField()/getDeclaredField()
 *    - 获取成员方法：getMethod()/getDeclaredMethod()
 *    - 获取内部类：getClasses()/getDeclaredClasses()
 *    - public和declared方法区别：public方法只获取公有成员，declared方法可获取所有包括私有成员
 *    - 面试考点：public方法与declared方法的区别，父类成员的获取
 *
 * 4. 反射调用与访问控制
 *    - setAccessible(true)：绕过访问权限控制，允许访问私有成员
 *    - 属性访问：field.get(obj)/field.set(obj, value)
 *    - 方法调用：method.invoke(obj, args...)
 *    - 构造对象：constructor.newInstance(args...)
 *    - 面试考点：如何处理私有成员访问，反射调用异常处理
 *
 * 5. 反射的性能问题
 *    - 性能开销：反射调用比直接调用慢约100-200倍
 *    - 性能优化：缓存Class和Method对象，减少重复获取
 *    - setAccessible(true)：除了绕过权限检查，还可提高反射性能
 *    - JIT优化：在热点代码中，JIT可能对反射调用进行优化
 *    - 面试考点：反射的性能开销及优化方案，如何在关键代码中降低反射开销
 *
 * 6. 反射与泛型
 *    - 泛型擦除：Java的泛型是伪泛型，编译后类型信息被擦除
 *    - Type体系：通过ParameterizedType等接口获取泛型信息
 *    - 获取泛型类型：getGenericSuperclass()/getGenericInterfaces()
 *    - 获取泛型参数：getActualTypeArguments()
 *    - 面试考点：如何在运行时获取泛型类型信息，常见框架中的应用
 *
 * 7. 反射与注解
 *    - 运行时注解：保留策略为RetentionPolicy.RUNTIME的注解可通过反射获取
 *    - 获取注解：getAnnotation()/getAnnotations()/getDeclaredAnnotation()
 *    - 处理注解：基于反射获取注解及其属性值并进行相应处理
 *    - 注解处理器：编译期间处理注解的另一种机制（非反射）
 *    - 面试考点：运行时如何获取和处理注解，常见框架中的注解处理机制
 *
 * 8. Android中的反射应用
 *    - 插件化开发：反射调用未在接口中声明的方法
 *    - 注解处理：ButterKnife、Dagger等框架的基础
 *    - 隐藏API访问：访问系统非公开API
 *    - Hook技术：替换系统类中的方法实现
 *    - ContentProvider：在URI匹配时可能使用反射分发到对应方法
 *    - 面试考点：Android中反射使用的限制和优化，特别是Android P以上版本
 *
 * 9. Android中反射的限制
 *    - 性能：移动设备资源有限，反射开销更为明显
 *    - API限制：从Android P开始，对非SDK接口的反射访问受限
 *    - 解决方案：预编译/注解处理器替代反射，使用官方提供的API
 *    - 面试考点：如何在高版本Android中合理使用反射，避开限制
 *
 * 三、ClassLoader和反射相关面试题
 *
 * 1. 什么是双亲委派模型？为什么需要这种模型？
 *    答：双亲委派模型是指当一个类加载器接收到类加载请求时，它首先会把这个请求委派给父类加载器，
 *        每个父类加载器都会采用同样的方式，直到请求传递到最顶层的启动类加载器。只有当父加载器无法完成加载请求时，
 *        子加载器才会尝试自己加载。
 *        
 *        需要这种模型的原因：
 *        1) 确保Java核心类库的类型安全：防止用户自定义的类替换Java核心类库的类
 *        2) 确保类的唯一性：同一个类在同一个类加载器命名空间中只会被加载一次
 *
 * 2. Class.forName()和ClassLoader.loadClass()有什么区别？
 *    答：主要区别在于：
 *        1) Class.forName()会执行类的初始化（静态代码块和静态变量赋值），而ClassLoader.loadClass()默认不会初始化类
 *        2) Class.forName()使用调用者的类加载器加载类，ClassLoader.loadClass()使用指定的类加载器
 *        3) Class.forName()有三参数版本，可以指定是否初始化和使用哪个类加载器
 *        
 *        典型应用：JDBC驱动加载通常使用Class.forName()，因为需要执行驱动类中的静态代码块来注册驱动
 *
 * 3. Android中的类加载器与Java中的有什么区别？
 *    答：主要区别：
 *        1) Android使用PathClassLoader和DexClassLoader代替Java中的URLClassLoader
 *        2) Android中加载的是dex文件（Dalvik可执行文件），而非直接加载class文件
 *        3) Android中的PathClassLoader用于加载已安装应用的dex，DexClassLoader可加载外部dex/apk/jar
 *        4) 自Android 8.0起，PathClassLoader和DexClassLoader的实现代码已合并，仅保留API兼容性
 *
 * 4. 热修复原理中，为什么补丁包的类能替换原有的类？
 *    答：热修复基于类加载器的工作原理：
 *        1) Android中使用PathClassLoader加载已安装的dex文件
 *        2) ClassLoader在加载类时，通过DexPathList中的dexElements数组按顺序查找类
 *        3) 热修复技术（如Tinker）在应用启动时通过反射将补丁dex插入到dexElements数组前面
 *        4) 由于类加载时会按数组顺序搜索，找到补丁中的类后就不再查找，原来有bug的类被跳过
 *        5) 关键是补丁包必须在类被首次加载前完成注入，否则类的Class对象已经生成，无法替换
 *
 * 5. 反射的主要应用场景有哪些？为什么需要反射机制？
 *    答：主要应用场景：
 *        1) 框架开发：如Spring通过反射创建Bean实例，Retrofit解析接口方法
 *        2) 动态代理：如AOP面向切面编程
 *        3) 注解处理：运行时注解需要反射获取和处理
 *        4) 动态加载类：如插件化开发中动态加载新功能
 *        5) 访问私有成员：测试或特殊场景需要访问类的私有成员
 *        
 *        需要反射的原因：允许程序在运行时检查和修改自身的行为，提供了更灵活的编程方式，
 *        使得很多框架能够以通用的方式处理不同的类，无需在编译时知道具体的类型。
 *
 * 6. 反射的主要性能问题及优化方案？
 *    答：性能问题：
 *        1) 反射调用比直接调用慢约100-200倍（主要是方法查找和访问检查开销）
 *        2) 对于频繁调用的代码，反射开销相当明显
 *        
 *        优化方案：
 *        1) 缓存反射对象：缓存Class、Method、Field等对象，避免重复获取
 *        2) 使用setAccessible(true)：绕过访问检查可提高性能
 *        3) 考虑替代方案：如注解处理器在编译期生成代码，避免运行时反射
 *        4) 限制反射范围：只在必要的地方使用反射
 *
 * 7. 什么情况下需要打破双亲委派模型？如何打破？
 *    答：需要打破的情况：
 *        1) SPI机制：如JDBC中接口由Bootstrap ClassLoader加载，实现类由应用类加载器加载
 *        2) 热部署/热更新：需要重新加载已经加载过的类
 *        3) OSGi等模块化系统：不同模块使用不同的类加载器隔离
 *        4) 自定义类加载逻辑：需要特殊的类加载顺序或规则
 *        
 *        打破方式：
 *        1) 重写ClassLoader.loadClass()方法，改变委派逻辑
 *        2) 使用线程上下文类加载器（Thread.currentThread().getContextClassLoader()）
 *        3) 使用自定义父加载器（非默认的父子关系）
 *
 * 8. Android中，如何获取泛型的实际类型？
 *    答：由于Java泛型存在类型擦除，需要通过反射API获取泛型信息：
 *        1) 获取泛型父类：getGenericSuperclass()
 *        2) 获取泛型接口：getGenericInterfaces()
 *        3) 转换为参数化类型：(ParameterizedType)
 *        4) 获取实际类型参数：getActualTypeArguments()
 *        
 *        示例代码：
 *        ```java
 *        class MyClass extends ArrayList<String> {
 *            public Type getElementType() {
 *                Type superclass = getClass().getGenericSuperclass();
 *                ParameterizedType paramType = (ParameterizedType) superclass;
 *                return paramType.getActualTypeArguments()[0]; // 返回String.class
 *            }
 *        }
 *        ```
 *
 * 9. Android P对反射的限制有哪些？如何应对？
 *    答：Android P(API 28)及以上的限制：
 *        1) 限制对非SDK接口的访问，包括反射调用私有或隐藏API
 *        2) 分为黑名单、灰名单和白名单，黑名单接口完全禁止访问
 *        3) 违反限制会导致崩溃或报错
 *        
 *        应对方案：
 *        1) 使用公开的SDK API替代隐藏API
 *        2) 在AndroidManifest.xml中添加豁免声明（仅限部分接口且不推荐）：
 *           ```xml
 *           <application android:appComponentFactory="androidx.core.app.CoreComponentFactory"
 *                        android:debuggable="true">
 *           ```
 *        3) 适配推荐的新API，如AppComponentFactory替代反射创建四大组件
 *        4) 针对特定设备开发的应用可以考虑与设备厂商合作提供特殊权限
 *
 * 10. Java类的生命周期包括哪些阶段？每个阶段做什么？
 *     答：Java类的生命周期包括5个阶段：
 *         1) 加载：通过类名获取二进制字节流，并转换为方法区的运行时数据结构，创建Class对象
 *         2) 验证：确保字节流符合JVM规范，进行文件格式、元数据、字节码、符号引用验证
 *         3) 准备：为类变量（static成员）分配内存并设置初始值（零值，如int为0）
 *         4) 解析：将常量池内的符号引用替换为直接引用（内存地址）
 *         5) 初始化：执行类构造器<clinit>方法，包括静态变量赋值和静态代码块，顺序按源码中出现顺序
 */
public class ClassLoaderDoc {
    // 这是一个文档类，只包含注释，没有实际代码
} 